var restify = require('restify');
var mongojs = require('mongojs');
var async = require('async');
var util = require('util');
var request = require('request');
const tenpay = require('tenpay');
var crypto = require('crypto');
var fs = require('fs');
var ObjectId = mongojs.ObjectId;


// MD5加密
function md5Encrypt(str) {
  var hasher = crypto.createHash("md5");
  hasher.update(str);
  encryptString = hasher.digest('hex');
  return encryptString;
}
// console.log(md5Encrypt('abc'));

// 随机订单ID
function randomOrderId() {
  var date = new Date();
  return 'ORDER' + date.getFullYear() + '' + date.getMonth() + '' +
    date.getDate() + '' + date.getHours() + '' +
    date.getMinutes() + '' + date.getSeconds() +
    + '' + (Math.floor(Math.random() * 1000));
}

// 服务启动的端口号
var server_port = '8088';

// MongoDB服务的地址和端口及数据库名称
var mongo_user_name = 'root';
var mongo_user_password = 'congmi123,.';
var mongo_db_url = '121.43.177.197:27017';
var mongo_db_database = 'sjb';

// 连接数据库
var mdb = mongojs(util.format('%s/%s', mongo_db_url, mongo_db_database), ['room', 'match', 'votes', 'user', 'order']);

// MongoDB的表名
var db_table_match = 'match';
var db_table_room = 'room';
var db_table_user = 'user';

// 赛事接口地址
var path_match = '/match';
var path_room = '/room';
var path_user = '/user';
var path_order = '/order';

// 小程序信息
var app_id = 'wx13709b4786827909'//'wx8eba34700de37807';
var app_secret = '92fb89a98a7ea59824c024ddcdfd0411'//'704a704cf57c2460c4006146f9953328';

// access token
var access_token_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${app_id}&secret=${app_secret}`;
var access_token = '';
var access_token_time = 0;// 更新token的时间

// 支付
const pay_config = {
  appid: app_id,
  mchid: '1295379301',
  partnerKey: 'idarenhui44444444444444444444sjb',
  pfx: require('fs').readFileSync('./cert/apiclient_cert.p12'),
  notify_url: 'http://localhost:8088/',
  spbill_create_ip: ''
};
// 方式一
const api = new tenpay(pay_config);
// 沙盒模式(用于微信支付验收)
// const sandboxAPI = await tenpay.sandbox(config);

// 创建rest服务
var server = restify.createServer({
  name: 'sjb-beer',
  version: '1.0.0'
});

// 服务配置
server.use(restify.plugins.queryParser({ mapParams: true }));
server.use(restify.plugins.bodyParser({ mapParams: true }));

// 公共函数
function sortCreateTime(a, b) {
  return a.create_time - b.create_time;
}

/**
 * 一共5个rest接口，其中4个查询接口，1个提交接口
 */
// 接口1: 查询赛事列表接口
server.get(util.format('%ss', path_match), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*')
  mdb.match.find({ end: 0 }, function (err, _matchs) {
    if (err) {
      res.send([]);
      return next();
    } else {
      var joined_matchs = [];
      var not_joined_matchs = [];
      async.map(_matchs, function (item, done) {
        mdb.room.find({ match_id: item._id.toString() }, function (err, rooms) {
          var c_rooms = rooms.filter(r => r.creator_uid == req.params.uid);
          if (c_rooms && c_rooms.length > 0) {
            // 创建者
            joined_matchs.push(item);
            done(null, null);
          } else {
            // 是否加入
            mdb.votes.findOne({ uid: req.params.uid, match_id: item._id.toString() }, function (err, vote) {
              if (vote) {
                joined_matchs.push(item);
              } else {
                not_joined_matchs.push(item);
              }
              done(null, null);
            });
          }
        });
      }, function (err, results) {
        if (err) {
          console.log('查询赛事列表接口: ' + err);
          res.send({
            error: "查询失败!"
          });
        } else {
          var ret_matchs = req.params.joined == 'true' ? joined_matchs : not_joined_matchs;
          res.send(ret_matchs.sort((a, b) => {
            if (a.start_time == b.start_time) {
              return a.create_time - b.create_time;
            }
            return a.start_time - b.start_time;
          }));
        }
        return next();
      });
    }
  });
});

// 接口1.1: 添加赛事
server.post(path_match, function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*')
  mdb.match.findOne({ home_team: req.params.home_team, custom_team: req.params.custom_team, start_time: req.params.start_time }, function (err, match) {
    if (match) {
      console.log(match)
      res.send({
        error: '赛事冲突!'
      })
      return next()
    } else {
      mdb.match.save({
        home_team: req.params.home_team, // '俄罗斯',
        home_team_logo: req.params.home_team_logo, // '',
        custom_team: req.params.custom_team, // '乌拉圭',
        custom_team_logo: req.params.custom_team_logo, // '',
        start_time: new Date(req.params.start_time).getTime(), // new Date(), // 比赛开始时间
        category: req.params.category, //  小组赛   16强赛  8强赛 4强 半决赛   决赛  3、4名决赛
        end: req.params.end ? 1 : 0, // 0, // 0 未开始 1 比赛结束
        final: 0, // 0 主胜 1 客胜 2 平局
        final_goals: '0:0',
        create_time: new Date().getTime(),
        last_modified_time: new Date().getTime()
      })
      res.send({})
      return next()
    }
  });
});

// 接口1.2: 查询所有赛事
server.get(util.format('%ss/all', path_match), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*')
  mdb.match.find({}, function (err, _matchs) {
    res.send(_matchs);
    return next();
  });
});


// 更新赛事结果
// 参数：
// 1. status:  0 未开始 1 正在比赛 2 比赛结束
// 2. final：  0 主胜 1 客胜 2 平局
// 3. final_goals:  比分 1:2
server.post(util.format('%s/:mid/final', path_match), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.match.findOne({ _id: ObjectId(req.params.mid) }, function (err, _match) {
    if (!_match) {
      res.send({ error: '赛事不存在' });
      return next();
    }
    if (_match.end == 1) {
      res.send({
        error: '赛事已经结束!无法更新状态'
      })
      return next();
    }
    mdb.match.update({ _id: ObjectId(req.params.mid) }, {
      $set: {
        end: req.params.end ? 1 : 0,
        final: req.params.end ? parseInt(req.params.final) : 0,
        final_goals: req.params.end ? req.params.final_goals : '0:0',
        final_time: req.params.end ? new Date().getTime() : '',
        last_modified_time: new Date().getTime()
      }
    }, function (err, match) {
      if (!req.params.end) {
        res.send('比赛未结束，不会更新下注信息');
        return next();
      }
      // 更新房间状态
      mdb.room.update({ match_id: req.params.mid }, {
        $set: {
          end: 1,
          last_modified_time: new Date().getTime()
        }
      }, function (err, ok) {
        console.log(`更新房间${req.params.mid}状态:`, ok);
        // 更新投票状态和发放勋章
        mdb.votes.find({ match_id: req.params.mid }, function (err, _votes) {
          var total_beers = 0;
          var hit_total_beers = 0;
          _votes.forEach((v) => {
            total_beers += parseInt(v.out_beers);
            if (v.vote == parseInt(req.params.final)) {
              hit_total_beers += parseInt(v.out_beers);
            }
          });
          if (_votes && _votes.length > 0) {
            async.map(_votes, function (item, done) {
              var isHit = parseInt(item.vote) == parseInt(req.params.final); // 是否命中
              var hitBeers = total_beers > 0 && isHit ? Math.floor(total_beers * item.out_beers / hit_total_beers) : 0;// 命中获得的奖金
              var inBeers = hitBeers - Math.floor((hitBeers > item.out_beers ? hitBeers - item.out_beers : 0) * 0.1);
              console.log(total_beers, hit_total_beers, hitBeers, inBeers);
              mdb.votes.update({ _id: ObjectId(item._id) }, {
                $set: {
                  hit: isHit ? 1 : 0, // 是否命中
                  end: 1, // 是否开奖
                  in_beers: inBeers, // 本次开奖后获取的啤酒数
                  last_modified_time: new Date().getTime()
                }
              }, function (err, res) {
                // 更新用户的勋章
                mdb.user.update({ uid: item.uid }, {
                  $inc: {
                    beers: inBeers,
                    win_times: isHit ? 1 : 0,
                    lose_times: !isHit ? 1 : 0
                  }
                }, function (err, ok) {
                  done(err);
                });
              });
            }, function (err) {
              if (err) {
                console.log('更新赛事结果', err);
                res.send({ error: '更新状态异常' });
                return next();
              }
              res.send({});
              return next();
            });
          }
        });
      });
    });
  });
});

// 接口3: 房间详情信息
server.get(util.format('%s/:rid', path_room), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.room.findOne({ _id: ObjectId(req.params.rid) }, function (err, room) {
    if (!room) {
      res.send({ error: '未找到相关房间信息' });
      return next();
    }
    console.log(room._id.toString());
    async.parallel({
      slefVotes: function (cb) {
        if (!req.params.uid) {
          cb(null, { vote: -1, out_beers: 0 });
          return;
        }
        mdb.votes.findOne({ room_id: room._id.toString(), uid: req.params.uid }, function (err, _vote) {
          cb(err, _vote ? _vote : { vote: -1, out_beers: 0 });
        });
      },
      homeVotes: function (cb) {
        mdb.votes.find({ room_id: room._id.toString(), vote: 0 }, function (err, _votes) {
          if (!_votes) {
            cb(err, { data: [], count: 0 });
          } else {
            var users = [];
            async.map(_votes, function (item, done) {
              mdb.user.findOne({ uid: item.uid }, function (err, user) {
                if (user) {
                  users.push({
                    uid: user.uid,
                    avatar: user.avatar,
                    nick_name: user.nick_name,
                    out_beers: item.out_beers,
                  });
                }
                done(err);
              })
            }, function (err) {
              cb(err, { data: users, count: users.length });
            })
          }
        })
      },
      customVotes: function (cb) {
        mdb.votes.find({ room_id: room._id.toString(), vote: 1 }, function (err, _votes) {
          console.log("customVotes", _votes);
          if (!_votes) {
            cb(err, { data: [], count: 0 });
          } else {
            var users = [];
            async.map(_votes, function (item, done) {
              mdb.user.findOne({ uid: item.uid }, function (err, user) {
                if (user) {
                  users.push({
                    uid: user.uid,
                    avatar: user.avatar,
                    nick_name: user.nick_name,
                    out_beers: item.out_beers,
                  });
                }
                done(err);
              });
            }, function (err) {
              cb(err, { data: users, count: users.length });
            });
          }
        });
      },
      midVotes: function (cb) {
        mdb.votes.find({ room_id: room._id.toString(), vote: 2 }, function (err, _votes) {
          console.log(_votes);
          if (!_votes) {
            cb(err, { data: [], count: 0 });
          } else {
            var users = [];
            async.map(_votes, function (item, done) {
              mdb.user.findOne({ uid: item.uid }, function (err, user) {
                if (user) {
                  users.push({
                    uid: user.uid,
                    avatar: user.avatar,
                    nick_name: user.nick_name,
                    out_beers: item.out_beers,
                  });
                }
                done(err);
              });
            }, function (err) {
              cb(err, { data: users, count: users.length });
            });
          }
        });
      },
      match: function (cb) {
        mdb.match.findOne({ _id: ObjectId(room.match_id) }, function (err, match) {
          cb(err, match);
        });
      }

    }, function (err, result) {
      var totalUsers = result.homeVotes.count + result.customVotes.count + result.midVotes.count;
      var homeVotesPerc = totalUsers > 0 ? parseInt(result.homeVotes.count * 100 / totalUsers) : 0;
      var customVotesPrec = totalUsers > 0 ? parseInt(result.customVotes.count * 100 / totalUsers) : 0;
      room.match = result.match;
      room.votes = {
        self_vote: result.slefVotes.vote,
        self_vote_beers: result.slefVotes.out_beers,
        votes_users: totalUsers,
        home_votes: result.homeVotes.data.sort(sortCreateTime),
        home_votes_users: result.homeVotes.count,
        custom_votes: result.customVotes.data.sort(sortCreateTime),
        custom_votes_users: result.customVotes.count,
        home_votes_percent: homeVotesPerc,
        custom_votes_percent: customVotesPrec,
        mid_votes: result.midVotes.data.sort(sortCreateTime),
        mid_votes_users: result.midVotes.count,
        mid_votes_percent: (100 - customVotesPrec - homeVotesPerc)
      };
      res.send(room);
      return next();
    });
  });
});

// 接口3.1: 创建房间
server.post(path_room, function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.room.findOne({ match_id: req.params.match_id, creator_uid: req.params.uid }, function (err, room) {
    if (room) {
      res.send({
        error: '您已经创建过该比赛的房间了！'
      });
      return next();
    } else {
      // 判断比赛状态
      mdb.match.findOne({ _id: ObjectId(req.params.match_id) }, function (err, match) {
        if (err || !match) {
          res.send({
            error: '系统异常或比赛不存在!'
          });
          return next();
        }
        var end = 0;
        var now = new Date().getTime();
        if (match.start_time < now) {
          end = 1;
        }

        mdb.room.save({
          name: req.params.name, // '房间名称',
          creator_uid: req.params.uid, // '创建人用户id',
          match_id: req.params.match_id, // '123',
          end: end, // 0, // 0 竞猜中 1 竞猜结束
          create_time: new Date().getTime(),
          last_modified_time: new Date().getTime()
        }, function (err, room) {
          res.send(room);
          return next();
        });
      });
    }
  });
});

// 接口4: 房间列表 
// uid: 
// end: true/false
server.get(util.format('%ss', path_room), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  var rooms = [];
  var roomIds = new Set();
  async.parallel({
    createdRooms: function (cb) {
      mdb.room.find({ creator_uid: req.params.uid }, // , end: req.params.end ? 1 : 0 
        function (err, _rooms) {
          // _rooms.forEach(e => {
          //   roomIds.add(e._id.toString());
          // });
          // 通过比赛状态判断
          async.map(_rooms, function (_room, callback) {
            mdb.match.findOne({ _id: ObjectId(_room.match_id) }, function (err1, m) {
              var _end = req.params.end ? 1 : 0;
              if (m && m.end == _end) {
                roomIds.add(_room._id.toString());
              }
              callback(err1);
            });
          }, function (err2) {
            console.log(err2);
            cb(err2);
          });
        });
    },
    joinedRooms: function (cb) {
      mdb.votes.find({ uid: req.params.uid, end: req.params.end ? 1 : 0 },
        function (err, votes) {
          votes.forEach(e => {
            roomIds.add(e.room_id);
          });
          cb(err);
        });
    }
  }, function (err) {
    if (err) {
      res.send([]);
      return next();
    }
    async.map(roomIds, function (room_id, callback) {
      mdb.room.findOne({ _id: ObjectId(room_id) }, function (err, room) {
        // 并行执行
        if (err || !room) {
          // 不存在room
          callback(err);
          return;
        }
        async.parallel({
          slefVotes: function (cb) {
            mdb.votes.findOne({ room_id: room_id, uid: req.params.uid }, function (err, _vote) {
              cb(err, _vote ? _vote : { vote: -1, out_beers: 0, in_beers: 0 });
            });
          },
          homeVotes: function (cb) {
            mdb.votes.count({ room_id: room_id, vote: 0 }, function (err, _votes) {
              if (err) {
                cb(err, 0);
              } else {
                cb(null, _votes ? _votes : 0);
              }
            });
          },
          customVotes: function (cb) {
            mdb.votes.count({ room_id: room_id, vote: 1 }, function (err, _votes) {
              if (err) {
                cb(err, 0);
              } else {
                cb(null, _votes ? _votes : 0);
              }
            });
          },
          midVotes: function (cb) {
            mdb.votes.count({ room_id: room_id, vote: 2 }, function (err, _votes) {
              if (err) {
                cb(err, 0);
              } else {
                cb(null, _votes ? _votes : 0);
              }
            });
          },
          match: function (cb) {
            mdb.match.findOne({ _id: ObjectId(room.match_id) }, function (err, match) {
              cb(err, match);
            });
          }
        }, function (err, result) {
          var totalUsers = result.homeVotes + result.customVotes + result.midVotes;
          var homeVotesPerc = totalUsers > 0 ? parseInt(result.homeVotes * 100 / totalUsers) : 0;
          var customVotesPrec = totalUsers > 0 ? parseInt(result.customVotes * 100 / totalUsers) : 0;
          room.match = result.match;
          room.votes = {
            self_vote: result.slefVotes.vote,
            self_vote_beers: result.slefVotes.out_beers,
            self_goals: result.slefVotes.in_beers,
            votes_users: totalUsers,
            home_votes_users: result.homeVotes,
            custom_votes_users: result.customVotes,
            home_votes_percent: homeVotesPerc,
            custom_votes_percent: customVotesPrec,
            mid_votes_users: result.midVotes,
            mid_votes_percent: (100 - customVotesPrec - homeVotesPerc)
          };
          rooms.push(room);
          callback(err);
        });
      });
    }, function (err) {
      if (!err) {
        res.send(rooms.sort((a, b) => {
          if (a.match.start_time == b.match.start_time) {
            return a.create_time - b.create_time;
          }
          return a.match.start_time - b.match.start_time;
        }));
        return next();
      } else {
        console.log(err);
        res.send([]);
        return next();
      }
    });
  });
});

// 接口4.1 获取所有房间列表
server.get(util.format('%ss/all', path_room), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.room.find({}).sort({ create_time: 1 }, function (err, doc) {
    res.send(doc);
    return next();
  });
});

// 接口5: 提交投票信息
server.post(util.format('%s/:rid/vote', path_room), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  if (!req.params.rid || !req.params.uid || !req.params.match_id) {
    res.send({
      error: '请求的参数错误!'
    });
    return next();
  }

  // 判断比赛状态
  mdb.match.findOne({ _id: ObjectId(req.params.match_id) }, function (err, match) {
    if (!match) {
      res.send({
        error: '比赛不存在!'
      });
      return next();
    }
    var now = new Date().getTime();
    if (match.start_time < now) {
      res.send({
        error: '比赛已经开始，无法参与竞猜!'
      });
      return next();
    }

    // 获取用户信息
    mdb.user.findOne({ uid: req.params.uid }, function (err, user) {
      if (!user) {
        res.send({ error: '用户不存在' });
        return next();
      }
      // 判断是否投票
      mdb.votes.findOne({ uid: req.params.uid, room_id: req.params.rid }, function (err, vote) {
        if (vote) {
          res.send({
            error: '您已经参与了该房间的竞猜，请勿重复参与'
          });
          return next();
        } else {
          var vote_beers = parseInt(req.params.beers);
          var user_beers = parseInt(user.beers);

          // 检查剩余勋章数
          if (vote_beers <= 0) {
            res.send({ error: '投入的勋章不能小于一个' });
            return next();
          }

          if (vote_beers > user_beers) {
            res.send({ error: '您的勋章不够了，请先购买足够的勋章~' });
            return next();
          }

          // 扣除用户的勋章
          mdb.user.update({ uid: req.params.uid }, {
            $set: {
              beers: user_beers - vote_beers,
              last_modified_time: new Date().getTime()
            }
          }, function (err, result) {
            console.log(`扣除用户${user.uid}的${vote_beers}个勋章成功`);
            mdb.votes.save({
              uid: req.params.uid, // '用户uid',
              vote: parseInt(req.params.vote), // 0, //  支持对象 0 主队 1 客队 2 平局
              room_id: req.params.rid, // '房间id',
              match_id: req.params.match_id,
              out_beers: parseInt(req.params.beers), // '支持的啤酒数量'
              hit: 0, // 是否命中
              end: 0, // 是否开奖
              in_beers: 0, // 本次开奖后获取的啤酒数
              create_time: new Date().getTime(),
              last_modified_time: new Date().getTime()
            }, function (err, ok) {
              if (err) {
                res.send({ error: '投票失败,系统错误' });
                return next();
              }
              res.send({});
              return next();
            });
          });
        }
      });
    });
  });
});

// 接口2: 查询个人信息
server.get(util.format('%s/:uid', path_user), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*')
  mdb.user.findOne({ uid: req.params.uid }, function (err, user) {
    if (!user) {
      res.send({ error: '用户不存在' });
    } else {
      res.send(user);
    }
    return next();
  });
});

// 接口6.1 微信用户登陆
// 参数：
// 1. code:
// 2. nick_name:
// 3. avatar: 
// 4: from_uid: 分享的用户
server.post('/login', function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  var auth_url = util.format('https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code', app_id, app_secret, req.params.code);
  request(auth_url, function (error, response, body) {
    console.log('error:', error); // Print the error if one occurred
    console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
    console.log('body:', JSON.parse(body)); // Print the HTML for the Google homepage.
    var openid = JSON.parse(body).openid;
    if (error) {
      res.send({ error: '登陆失败!' });
      return next();
    }

    // 登陆成功, 注册用户
    mdb.user.findOne({ uid: openid }, function (err, user) {
      if (user) {
        console.log('用户已登陆');
        res.send({ uid: openid });
        return next();
      } else {
        mdb.user.save({
          uid: openid, // '用户uid',
          nick_name: req.params.nick_name, // '用户昵称',
          avatar: req.params.avatar, // '123',
          beers: 5, // 初始化5个勋章
          win_times: 0, // 成功次数
          lose_times: 0, // 失败次数
          status: 0, // 0 正常
          create_time: new Date().getTime(),
          last_out_money_time: 0, //最后一次提现的时间
          last_modified_time: new Date().getTime()
        }, function (err, r) {
          if (err) {
            console.log(err);
            res.send({ error: '注册用户失败' });
            return next();
          }

          // 分享的用户勋章+1
          if (req.params.from_uid) {
            mdb.user.update({ uid: req.params.from_uid }, {
              $inc: {
                beers: 5,
              }
            }, function (err, ok) {
              res.send({ uid: openid });
              return next();
            });
          } else {
            res.send({ uid: openid, first_login: true });
            return next();
          }
        });
      }
    });
  });
});

// 接口7 提现
// 参数：
// 1. uid: 用户的openid
// 2. beers: 提现的勋章数量
server.post('/beers/out', function (req, res, next) {
  if (!req.params.uid || !req.params.beers) {
    res.send({
      error: '请求的提现参数错误'
    });
    return next();
  }

  var to_out_beers = parseInt(req.params.beers);
  if (to_out_beers <= 0) {
    res.send({
      error: '请求的提现参数错误'
    });
    return next();
  }

  // 检查uid是否为本平台用户
  mdb.user.findOne({ uid: req.params.uid }, function (err, user) {
    if (!user) {
      res.send({
        error: '用户不存在'
      });
      return next();
    }

    var user_beers = parseInt(user.beers);
    if (to_out_beers >= user_beers) {
      res.send({
        error: '您可以提现的勋章不足'
      });
      return next();
    }

    if (user_beers <= 10) {
      res.send({ error: '您剩余的勋章不能小于或等于10个' });
      return next();
    }

    if (to_out_beers < 10) {
      res.send({ error: '提现的勋章数量不能低于10个' });
      return next();
    }

    // 先扣除平台的勋章
    mdb.user.update({ uid: req.params.uid }, {
      $set: {
        beers: user_beers - to_out_beers,
        last_out_money_time: new Date().getTime(), //最后一次提现的时间
        last_modified_time: new Date().getTime()
      }
    }, function (err, ok) {
      if (err) {
        res.send({ error: '系统错误,无法交易' });
        return next();
      }

      // 调用微信企业支付接口
      var order_id = randomOrderId();
      var amount = Math.floor(to_out_beers * 10);

      // 保存订单信息
      mdb.order.save({
        order_id: order_id,
        type: '用户提现',
        uid: req.params.uid,
        amount: amount,
        create_time: new Date().getTime(),
        last_modified_time: new Date().getTime()
      }, function (err, ok) {
        if (err) {
          console.log(err);
          // 回滚勋章数量
          mdb.user.update({ uid: req.params.uid }, {
            $set: {
              beers: user_beers,
              last_out_money_time: new Date().getTime(), //最后一次提现的时间
              last_modified_time: new Date().getTime()
            }
          }, function (err, ok) {
            res.send({ error: '提现失败' });
            return next();
          });
        }
        api.transfers({
          partner_trade_no: randomOrderId(),
          openid: req.params.uid,
          check_name: 'NO_CHECK',
          re_user_name: '',
          amount: amount,
          desc: '用户提现勋章*' + to_out_beers
        }).then(result => {
          console.log(result);
          if (result.return_code == 'SUCCESS') {
            res.send({});
            return next();
          }
          // 回滚勋章数量
          mdb.user.update({ uid: req.params.uid }, {
            $set: {
              beers: user_beers,
              last_out_money_time: new Date().getTime(), //最后一次提现的时间
              last_modified_time: new Date().getTime()
            }
          }, function (err, ok) {
            res.send({ error: '提现失败' });
            return next();
          });
        }, err => {
          console.log("error: ", err);
          // 回滚勋章数量
          mdb.user.update({ uid: req.params.uid }, {
            $set: {
              beers: user_beers,
              last_out_money_time: new Date().getTime(), //最后一次提现的时间
              last_modified_time: new Date().getTime()
            }
          }, function (err, ok) {
            res.send({ error: '提现失败' });
            return next();
          });
        });
      });
    });
  });

});


// 接口8： 充值接口
// 参数:
// 1. uid: 充值的用户id
// 2. beers: 充值数量
// 3. order_id: 订单号
server.post('/beers/in', function (req, res, next) {
  if (!req.params.uid || !req.params.beers) {
    res.send({
      error: '请求的充值参数错误'
    });
    return next();
  }

  var to_in_beers = parseInt(req.params.beers);
  if (to_in_beers <= 0) {
    res.send({
      error: '请求的充值参数错误'
    });
    return next();
  }

  // 检查uid是否为本平台用户
  mdb.user.findOne({ uid: req.params.uid }, function (err, user) {
    if (!user) {
      res.send({
        error: '指定的用户不存在'
      });
      return next();
    }

    if (!req.params.orderId || !/^ORDER2018\d+/.test(req.params.orderId)) {
      res.send({
        error: '请求的参数错误'
      });
      return next();
    }

    // TODO: 调用微信接口检查订单合法性
    api.orderQuery({
      // transaction_id, out_trade_no 二选一
      // transaction_id: '微信的订单号',
      out_trade_no: req.params.orderId
    }).then(result => {
      // console.log(result);
      //     { return_code: 'SUCCESS',
      // return_msg: 'OK',
      // appid: 'wx13709b4786827909',
      // mch_id: '1295379301',
      // nonce_str: 'Ae1esulMFY1J0z0j',
      // sign: '51EB27B142437E173BD9DE4FEF3FCF65',
      // result_code: 'SUCCESS',
      // openid: 'oVrT50Hu2mOLQ0csK1kb2Pe1JdTU',
      // is_subscribe: 'N',
      // trade_type: 'JSAPI',
      // bank_type: 'CFT',
      // total_fee: '100',
      // fee_type: 'CNY',
      // transaction_id: '4200000122201806252587859516',
      // out_trade_no: 'ORDER20185251756450102',
      // attach: '',
      // time_end: '20180625175655',
      // trade_state: 'SUCCESS',
      // cash_fee: '100',
      // trade_state_desc: '支付成功' }
      if (result.return_code == 'SUCCESS' && result.trade_state == 'SUCCESS') {
        // 更新用户的勋章
        var user_beers = parseInt(user.beers);
        mdb.user.update({ uid: req.params.uid }, {
          $set: {
            beers: user_beers + to_in_beers,
            last_in_money_time: new Date().getTime(), //最后一次充值的时间
            last_modified_time: new Date().getTime()
          }
        }, function (err, ok) {
          if (err) {
            res.send({
              error: '充值失败'
            });
            return next();
          }
          res.send({});
          return next();
        });
      } else {
        console.log(result);
        res.send({
          error: '充值失败'
        });
        return next();
      }
    }, err => {
      console.log(result);
      res.send({
        error: '充值失败'
      });
      return next();
    });
  });
});


// 接口9： 请求支付
server.post('/buy/pre', function (req, res, next) {
  var openid = req.params.uid;
  var beers = parseInt(req.params.beers);
  var price = parseFloat(req.params.price);
  if (!openid || !beers || !price) {
    res.send({
      error: '参数错误'
    });
    return next();
  }

  var order_id = randomOrderId();
  // 创建订单
  api.unifiedOrder({
    out_trade_no: order_id,
    body: '购买勋章*' + beers,
    total_fee: price * 100,
    openid: openid
  }).then((result) => {
    console.log(result);
    if (result.return_code == 'SUCCESS') {
      var payRequest = {
        appId: app_id,
        timeStamp: Math.floor(new Date().getTime() / 1000),
        nonceStr: result.nonce_str,
        package: `prepay_id=${result.prepay_id}`,
        signType: 'MD5'
      };
      var paySign = md5Encrypt(`appId=${payRequest.appId}&nonceStr=${payRequest.nonceStr}&package=${payRequest.package}&signType=${payRequest.signType}&timeStamp=${payRequest.timeStamp}&key=${pay_config.partnerKey}`);
      payRequest.paySign = paySign;
      mdb.order.save({
        order_id: order_id,
        type: '用户充值',
        ...payRequest,
        uid: openid,
        amount: price * 100,
        create_time: new Date().getTime(),
        last_modified_time: new Date().getTime()
      }, function (err, ok) {
        if (!err) {
          res.send({
            orderId: order_id,
            ...payRequest
          });
          return next();
        }
        console.log(err);
        res.send({ error: '系统错误' });
        return next();
      });
    } else {
      res.send({
        error: '创建微信支付订单失败'
      });
      return next();
    }
  }, err => {
    console.log("error:", err);
    res.send({
      error: '创建微信支付订单失败'
    });
    return next();
  });
});

// 接口10： 查询所有订单
server.get(util.format('%ss/all', path_order), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.order.find({}).sort({ last_modified_time: 1 }, function (err, doc) {
    res.send(doc);
    return next();
  });
});

// 接口11： 查询所有用户
server.get(util.format('%ss/all', path_user), function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  mdb.user.find({}).sort({ create_time: 1 }, function (err, doc) {
    res.send(doc);
    return next();
  });
});


// 接口12：获取页面二维码地址
server.post('/code/generate', function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  const cur = new Date().getTime();
  var room_id = req.params.roomId;
  var uid = req.params.uid;
  if (!room_id || !uid) {
    res.send({
      error: '参数错误'
    })
    next()
    return;
  }
  var qrcode_filename = `${room_id}_${uid}.png`
  if (cur - access_token_time > 3600) {
    // 3分钟刷新一次
    request(access_token_url, function (err, response, body) {
      if (!err && response.statusCode == 200) {
        access_token = JSON.parse(body).access_token;
        var url = `https://api.weixin.qq.com/wxa/getwxacode?access_token=${access_token}`;
        var requestBody = {
          path: `pages/room/room?fromUid=${uid}&id=${room_id}`,
          width: 160
        }
        request.post({ url: url, json: true, body: requestBody }, function (err1, response1, body1) {
          if (!err && response.statusCode == 200) {
            res.send({
              url: `/qrcode/${qrcode_filename}`
            });
            next();
          } else {
            res.send({
              error: '获取二维码失败'
            })
            next();
          }
        }).pipe(fs.createWriteStream(`./qrcode/${qrcode_filename}`));
      } else {
        console.log(err, response, body);
        res.send({
          error: '获取access token失败'
        });
        next();
      }
    });
  } else {
    var url = `https://api.weixin.qq.com/wxa/getwxacode?access_token=${access_token}`;
    var requestBody = {
      path: 'pages/room/room?fromUid=${uid}&id=${room_id}',
      width: 160
    }
    request.post({ url: url, json: true, body: requestBody }, function (err1, response1, body1) {
      console.log(url);
      if (!err && response.statusCode == 200) {
        res.send({
          url: `/qrcode/${qrcode_filename}`
        });
        next();
      } else {
        res.send({
          error: '获取二维码失败'
        })
        next();
      }
    }).pipe(fs.createWriteStream(`./qrcode/${qrcode_filename}`));
  }


});

// 文件代理
server.get('/file/proxy', function (req, res, next) {
  request(req.params.url, function (err, response, body) {
  }).pipe(res);
});

server.get('/qrcode/*', restify.plugins.serveStatic({
  directory: __dirname,
}))

// 赛事地址
// http://data.2018.sohu.com/game-schedule.html?index=3

server.listen(server_port, function () {
  console.log('%s listening at %s', server.name, server.url);
})
